package com.lhn;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 电商比价需求
 *
 * @author lhn
 * @date 2022/08/31 08:50
 * @since 1.0.0
 **/
public class CompletableFutureMallDemo {

    static List <NetMall> list = Arrays.asList(
            new NetMall("jd"),
            new NetMall("dangdang"),
            new NetMall("taobao"),
            new NetMall("pdd"),
            new NetMall("xianyu")
    );

    /**
     * step by step 一家家搜查
     * */
    public static List <String> getPrice(List <NetMall> list, String productName) {
        return list.stream().map(
                item -> String.format(
                        productName + " in %s price is %.2f", item.getNetMallName(),
                        item.calcPrice(productName))
        ).collect(Collectors.toList());
    }

    public static List <String> getPriceFuture(List <NetMall> list, String productName) {
        List<FutureTask<String>> futureTasks = new ArrayList <FutureTask<String>>();
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 3,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
                new ThreadPoolExecutor.DiscardOldestPolicy());
        threadPool.prestartAllCoreThreads(); // 预启动所有核心线程
        list.forEach(item -> {
            threadTask threadTask = new threadTask(item, productName);
            FutureTask <String> futureTask = new FutureTask <String>(threadTask);
            futureTasks.add(futureTask);
            threadPool.submit(futureTask);
        });
        List <String> collect = futureTasks.stream().map(item -> {
            try {
                return item.get();
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
        //清理线程池
        threadPool.shutdown();
        return collect;
    }

    public static List <String> getPriceByCompletableFuture(List <NetMall> list, String productName) {
        return list.stream().map(netMall -> CompletableFuture.supplyAsync(
                () -> String.format(
                        productName + " in %s price is %.2f", netMall.getNetMallName(), netMall.calcPrice(productName)))
        ).collect(Collectors.toList()).stream().map(CompletableFuture::join).collect(Collectors.toList());
    }



    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        List <String> stringList = getPrice(list, "mysql");
        stringList.forEach(System.out::println);
        long endTime = System.currentTimeMillis();
        System.out.println("---- costTime:" + (endTime - startTime) + "毫秒");

        long startTime2 = System.currentTimeMillis();
        List <String> stringList2 = getPriceByCompletableFuture(list, "mysql");
        stringList2.forEach(System.out::println);
        long endTime2 = System.currentTimeMillis();
        System.out.println("---- costTime:" + (endTime2 - startTime2) + "毫秒");

        long startTime3 = System.currentTimeMillis();
        List <String> stringList3 = getPriceFuture(list, "mysql");
        stringList3.forEach(System.out::println);
        long endTime3 = System.currentTimeMillis();
        System.out.println("---- costTime:" + (endTime3 - startTime3) + "毫秒");
    }

}

class threadTask implements Callable <String> {

    NetMall netMall;

    String productName;

    public threadTask() {
    }

    public threadTask(NetMall netMall, String productName) {
        this.netMall = netMall;
        this.productName = productName;
    }

    @Override
    public String call() throws Exception {
        return String.format(productName + " in %s price is %.2f", netMall.getNetMallName(), netMall.calcPrice(productName));
    }
}

class NetMall {

    private String netMallName;

    public String getNetMallName() {
        return netMallName;
    }

    public NetMall(String netMallName) {
        this.netMallName = netMallName;
    }

    public double calcPrice(String productName) {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
    }
}